﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace Red.GameData.Raw
{
    public partial class DataFile
    {
        /// <summary>
        /// Verify that a reload is needed for this file
        /// Basically this method rechecks the file modification date to make sure its different than the one that was seen when the file was loaded
        /// This is used as a additional verification step for the reloading as it was previously observed that the FileSystemWatcher is sometimes reporting to many files.
        /// </summary>
        public void VerifyReload()
        {
            try
            {
                var fileInfo = new System.IO.FileInfo(Path);
                if ( fileInfo.LastWriteTime != _fileTimeStamp )
                {
                    _newVersionDetected = true; // hint that we HAVE a new version of this file
                }
            }
            // unsafe: as this is IO code capture all complaints
            catch (Exception) {}
        }

        /// <summary>
        /// Capture the file's modification time stamp
        /// </summary>
        private void CaptureCurrentTimeStamp()
        {
            try
            {
                var fileInfo = new System.IO.FileInfo(Path);
                _fileTimeStamp = fileInfo.LastWriteTime;
            }
            // unsafe: as this is IO code capture all complaints
            catch (Exception) { }
        }

        /// <summary>
        /// Force a reload of this file. If file was modified all changes are lost.
        /// NOTE: this will cause local data loss if used without care.
        /// NOTE: new content will NOT be loaded if there's a reload request pending
        /// </summary>
        public void Reload(IGenericFileErrorReporter log)
        {
            // open file
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(Path);
            }
            catch (XmlException e)
            {
                // TODO: I didn't have time to do a proper loading support :(
                log.Error( "XML loading error:\n " + e.ToString() );
                return;
            }

            // delete existing objects
            _objectsInFile.Clear();

            // parse content
            foreach (XmlNode rootNodes in doc.ChildNodes)
            {
                int numObjects = rootNodes.ChildNodes.Count;
                int curObject = 0;
                foreach (XmlNode node in rootNodes.ChildNodes)
                {
                    // report file loading progress
                    log.FileProggres(curObject++, numObjects);

                    // load objects only
                    if (node.Name == "object")
                    {
                        var loadedObj = DataObject.LoadFromNode(this, log, node);
                        if (loadedObj != null)
                            _objectsInFile.Add(loadedObj);
                    }
                }
            }

            // file loaded
            _isModified = false;
            _newVersionDetected = false;

            // capture the file time stamp so we would be able to filter out reloading requests
            CaptureCurrentTimeStamp();
        }

        /// <summary>
        /// Save file to it's original path
        /// </summary>
        public void Save(IGenericFileErrorReporter log, bool force)
        {
            // the special "unassigned" file should never be saved
            if (Path == "<unassigned>")
                return;

            // don't save the unmodified files
            // DO NOT REMOVE THIS: we need to keep the modification tracking a really solid thing, without it people may loose local changes
            if (!_isModified && !force)         
                return;

            // start file context
            log.StartFile(Path);

            // prepare XML document in-memory
            XmlDocument xml = new XmlDocument();
            {
                XmlElement root = xml.CreateElement("objects");

                int numObjects = _objectsInFile.Count;
                int curObject = 0;
                foreach (var obj in _objectsInFile)
                {
                    // update file progress
                    log.FileProggres(curObject++, numObjects);

                    // create an object node and save it
                    var childXml = xml.CreateElement("object");
                    obj.SaveToNode(childXml);
                    root.AppendChild(childXml);
                }

                xml.AppendChild(root);
            }

            // save it to file
            try
            {
                xml.Save(Path);
            }
            catch (XmlException e)
            {
                // TODO: I didn't have time to do a proper loading support :(
                log.Error("XML saving error:\n " + e.ToString());
                return;
            }

            // reset modification flags
            _isModified = false;
            _newVersionDetected = false; // we just overridden it

            // capture the file time stamp so we would be able to filter out reloading requests
            CaptureCurrentTimeStamp();
        }
    }
}
